# -*- coding: utf-8 -*-
__author__ = 'vladbranzei'

from onlineutils import crypto
import cherrypy, time, logging

from cherrypy import response
from cherrypy import HTTPError
from onlineutils.web import validate, jsonify, has_scope
from freya.mapper.player_mapper import PlayerMapper
from freya.mapper.permission_mapper import PermissionMapper
from onlineutils import validator as v


class Freya(object):

    @jsonify
    def authorize(self, **kwargs):
        try:
            credentials = kwargs['credentials']
            password = kwargs['password']
            game = kwargs['game']
            if not v.validate_game(game):
                raise HTTPError(400, 'Wrong arguments')
            scopes = kwargs['scopes']
            scopes = v.validate_scopes(scopes)

            result = self._authorize(credentials, password, game, scopes)
            return result
        except KeyError as e:
            response.status = 400
            logging.exception(str(e))
            return "Missing arguments"
        except cherrypy.HTTPError as e:
            response.status = e.args[0]
            logging.exception(str(e))
            return e.args[1]
        except Exception as e:
            response.status = 500
            logging.exception(str(e))
            return "A server-side error occurred"

    def _authorize(self, credential, password, game, scopes):
        mapper = PlayerMapper()
        if mapper.check(credential, game, password):
            vid = mapper.foundUser.vid
            access_token, refresh_token = self._create_token(credential, game, scopes, vid)

            output = {}
            output['access_token'] = access_token
            output['refresh_token'] = refresh_token
            output['scopes'] = scopes
            return output
        else:
            vid = crypto.create_vid()
            result = mapper.create(vid, credential, game, password)
            if result:
               access_token, refresh_token = self._create_token(credential, game, scopes, vid)

               output = {}
               output['access_token'] = access_token
               output['refresh_token'] = refresh_token
               output['scopes'] = scopes

               return output
            else:
                response.status = 500


    @jsonify
    @validate
    @has_scope("auth")
    def authenticate(self, *kwargs):
        args = kwargs[0]
        try:
            credential = args['credentials']
            game = args['game']
            self._authenticate(credential, game)
            return "User found for game: " + game
        except KeyError as e:
            response.status = 400
            logging.exception(str(e))
            return "Missing arguments. exception: " + str(e)
        except HTTPError as e:
            response.status = e.code
            logging.exception(str(e))
            return "User not found for game " + game
        except Exception as e:
            response.status = e.code
            logging.exception(str(e))
            return "mata"

    def _authenticate(self, credential, game):
        mapper = PlayerMapper()
        result = mapper.check(credential, game)

        if result:
            return True
        else:
            raise cherrypy.HTTPError(404, 'Credential not found')

    @jsonify
    @validate
    @has_scope("auth")
    def change_password(self, *kwargs):
        args = kwargs[0]
        try:
            credentials = args['token'].split("|")[1]
            new_password = args['new_password']
            game = args['token'].split("|")[3]

            mapper = PlayerMapper()
            mapper.change_password(credentials, game, new_password)
            return "Password changed!"
        except KeyError as e:
            response.status = 400
            logging.exception(str(e))
            return "Missing arguments. exception: " + str(e)
        except HTTPError as e:
            response.status = e.code
            return str(e)
        except Exception as e:
            response.status = 500
            logging.exception(str(e))
            return "A server-side error occured: " + e(str)

    @jsonify
    @validate
    @has_scope("auth")
    def add_permissions(self, *kwargs):
        args = kwargs[0]
        try:
            credentials = args['credentials']
            game = args['token'].split("|")[3]
            permissions = args['permissions'].split()

            mapper = PermissionMapper()
            player_mapper = PlayerMapper()
            if player_mapper.check(credentials, game, None):
                result = mapper.add_permission(player_mapper.foundUser.vid, game, permissions)
                if result is True:
                    return "Permissions added"
            else:
                response.status = 404
                return "Not found"
        except KeyError as e:
            response.status = 400
            logging.exception(str(e))
            return "Missing arguments"
        except HTTPError as e:
            response.status = e.code
            logging.exception(str(e))
        except Exception as e:
            response.status = 500
            logging.exception(str(e))

    @jsonify
    @validate
    @has_scope("auth")
    def remove_permissions(self, *kwargs):
        args = kwargs[0]

        try:
            credentials = args['credentials']
            game = args['token'].split("|")[3]
            permissions = args['permissions'].split()

            mapper = PermissionMapper()
            player_mapper = PlayerMapper()
            if player_mapper.check(credentials, game, None):
                result = mapper.remove_permission(player_mapper.foundUser.vid, game, permissions)
                if result is True:
                    return "Permissions removed"
        except KeyError as e:
            response.status = 400
            logging.exception(str(e))
            return "Missing arguments"
        except cherrypy.HTTPError as e:
            response.status = e.code
            logging.exception(str(e))
        except Exception as e:
            response.status = 500
            return "A server-side error occurred"

    def _create_token(self, credential, game, scopes, vid):
        acc_tok = str(vid) + "|" + str(credential) + "|" + str(scopes) + "|" + str(game) + "|" + str(time.time()) + "|"
        access_token = acc_tok + crypto.encrypt(acc_tok)

        ref_tok = "refresh|" + str(vid) + "|" + str(credential) + "|" + str(scopes) + "|" + str(game) + "|" + str(time.time()) + "|"
        refresh_token = ref_tok + crypto.encrypt(ref_tok)

        return access_token, refresh_token